﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PlanProd.Contracts.Interfaces;
using PlanProd.Contracts;
using PlanProd.Data;
using Web.Framework.Svc;
using PlanProd.Contracts.enums;
using System.Transactions;
using PlanProd.InterfaceSAP.ServiceReferenceZMM_WS_NOVEDADES_PRODUCCION_SJ;
using PlanProd.Services.Clases;

namespace PlanProd.Services
{
    public class IncorporacionDeDesviosProcess
    {

        private TransactionScope CreateTransactionScope()
        {
            return new TransactionScope(TransactionScopeOption.Required, new TimeSpan(0, 50, 0));
        }

        public IncorporacionDeDesviosProcess()
        {
            OnNotify += new MensajeNotificacion(IncorporacionDeDesviosProcess_OnNotify);
        }

        public void IncorporacionDeDesviosProcess_OnNotify(string mensaje, IncorporacionDeDesviosProcess.TipoMensajeNotificacion tipoNotificacion)
        {
            // Grabo en base de datos
            var tmpTransaction = System.Transactions.Transaction.Current;

            System.Transactions.Transaction.Current = null;

            using (PlanProdEntities ctx = new PlanProdEntities())
            {
                DbPlanProdDesvioOrigenCorrida logCorrida = new DbPlanProdDesvioOrigenCorrida();
                ctx.DbPlanProdDesvioOrigenCorridas.AddObject(logCorrida);
                logCorrida.Nombre = NombreCorrida;
                logCorrida.Fecha = FechaCorrida;
                logCorrida.Mensaje = mensaje;
                logCorrida.FechaDesvio = FechaDesvio;
                ctx.SaveChanges();
            }

            System.Transactions.Transaction.Current = tmpTransaction;
        }

        public enum TipoMensajeNotificacion
        {
            Informacion = 0,
            Error = 1
        }

        public delegate void MensajeNotificacion(string mensaje, TipoMensajeNotificacion tipoNotificacion);

        public event MensajeNotificacion OnNotify;

        protected virtual void MensajeDeNotificacion(string mensaje, TipoMensajeNotificacion tipoNotificacion)
        {
            if (OnNotify != null)
            {
                OnNotify(mensaje, tipoNotificacion);
            }
        }

        /// <summary>
        /// Parametro de nombre de plan (puede ser por ejemplo SAN JUAN)
        /// </summary>
        public string NombrePlan { get; set; }

        public string NombreDestinoSap { get; set; }

        private string NombreCorrida { get; set; }

        private DateTime FechaCorrida { get; set; }

        private DateTime FechaDesvio { get; set; }

        public void IncorporarDesvios(DateTime fecha, ServiceOptions serviceOptions)
        {
            try
            {
                DateTime now = DateTime.Now;
                NombreCorrida = string.Format("Desvio de San Juan {0:dd/MM/yyyy HH:mm:ss}", now);
                FechaCorrida = now;
                FechaDesvio = fecha;

                // Validacion PSPLC-128
                if (now.Date <= fecha.Date)
                {
                    MensajeDeNotificacion(string.Format("No se puede procesar el desvio para la fecha {0:dd/MM/yyyy} ya que es una fecha mayor o igual al día de hoy {1:dd/MM/yyyy}", fecha, now), TipoMensajeNotificacion.Error);
                    return;
                }

                // Incorpora los desvios para una fecha, con la fecha obtengo la temporada
                // en NombrePlan: obtiene el like del nombre para obtener el plan de produccion, por ejemplo: san juan
                // luego por cada entrada voy eligiendo el plan y le cargo el movimiento            
                List<SanJuanRegistroDeDesvios> registrosDeDesvios = ObtenerDesviosDesdeSapAgrupadoPorFechaSumaCantidad(fecha);

                // Por cada grupo cargo la operación correspondiente en el plan correspondiente

                //..Obtengo la temporada a partir de la fecha

                List<DbTemporadaSemanaMes> temporadaSemanaMesList = null;
                using (TransactionScope tScope = CreateTransactionScope())
                {
                    using (PlanProdEntities ctx = new PlanProdEntities())
                    {
                        // TODO: hay temporadas solapadas y ambas activas, esto puede traer problemas
                        var dbTemporadas = ctx.DbTemporadas.Where(t => t.FechaInicio <= fecha && t.FechaFin > fecha).ToList();

                        if (dbTemporadas.Count == 0)
                        {
                            MensajeDeNotificacion(string.Format("No se encontró la temporada para la fecha {0}", fecha), TipoMensajeNotificacion.Error);
                            return;
                        }
                        
                        DbTemporada dbTemporada = null;

                        // Por cada registro proceso el desvio
                        MensajeDeNotificacion(string.Format("Existen para procesar {0} registros agrupados", registrosDeDesvios.Count), TipoMensajeNotificacion.Informacion);
                        foreach (SanJuanRegistroDeDesvios registroDeDesvios in registrosDeDesvios)
                        {
                            ObtenerDetalleDeTemporadas(ref temporadaSemanaMesList, dbTemporadas, ref dbTemporada, registroDeDesvios);
                                                       
                            if (temporadaSemanaMesList != null && temporadaSemanaMesList.Count > 0)
                            {
                                bool procesar = true;
                                if (!String.IsNullOrEmpty(NombreDestinoSap))
                                {
                                    if (NombreDestinoSap.ToLower() != registroDeDesvios.Destino.ToLower())
                                    {
                                        procesar = false;
                                    }
                                }

                                if (procesar)
                                {
                                    ProcesarDesvioDesdeSap(ctx, serviceOptions, dbTemporada, temporadaSemanaMesList, registroDeDesvios);
                                }
                            }
                        }

                        MensajeDeNotificacion("Fin del Proceso", TipoMensajeNotificacion.Informacion);
                        tScope.Complete();
                        
                    }
                }
            }
            catch (Exception ex)
            {
                MensajeDeNotificacion(ex.Message, TipoMensajeNotificacion.Error);
                throw;
            }
        }

        private static void ObtenerDetalleDeTemporadas(ref List<DbTemporadaSemanaMes> temporadaSemanaMesList, List<DbTemporada> dbTemporadas, ref DbTemporada dbTemporada, SanJuanRegistroDeDesvios registroDeDesvios)
        {
            if (dbTemporadas.Count > 1)
            {
                temporadaSemanaMesList = null;
                // la ubico con el mapeo externo
                dbTemporada = dbTemporadas.Where(t => t.MapeoTemporadaExterno == registroDeDesvios.TemporadaMapeoExterno).SingleOrDefault();
                if (dbTemporada != null)
                {
                    temporadaSemanaMesList = dbTemporada.TemporadaSemanaMes.ToList();
                }
            }
            else if (dbTemporadas.Count == 1)
            {
                if (dbTemporada == null)
                {
                    dbTemporada = dbTemporadas.Single();
                    if (dbTemporada != null)
                    {
                        temporadaSemanaMesList = dbTemporada.TemporadaSemanaMes.ToList();
                    }
                    else
                    {
                        temporadaSemanaMesList = null;
                    }
                }
            }
        }

        /// <summary>
        /// Procesa un registro de desvio
        /// (Podria devolver una lista de desvios y luego usar el servicio para guardar y aprobar masivo)
        /// </summary>
        /// <param name="ctx"></param>
        /// <param name="dbTemporada"></param>
        /// <param name="temporadaSemanaMesList"></param>
        /// <param name="registroDeDesvios"></param>
        private void ProcesarDesvioDesdeSap(PlanProdEntities ctx, ServiceOptions serviceOptions, DbTemporada dbTemporada, List<DbTemporadaSemanaMes> temporadaSemanaMesList, SanJuanRegistroDeDesvios registroDeDesvios)
        {
            // Tengo que obtener el plan (proveedor - con el tipo nombre, destino - del parametro, temporada - del parametro

            // Obtengo el destino en base a las relaciones
            DbPlanProduccion dbPlanDeProduccion = null;

            var dbDestinoList = ctx.DbDestinoes.FilterLogicalRemoved().Where(d => d.MapeoDestinoExterno.Contains(registroDeDesvios.Destino)).ToList();

            if (dbDestinoList.Count > 1)
            {
                List<DbDestino> dbDestinoList2 = new List<DbDestino>();
                // Analizo en detalle la lista
                bool existeDestinoUnico = false;
                bool destinoDuplicado = false;
                foreach (var dbDm in dbDestinoList)
                {
                    string[] destinoMapeoSplit = dbDm.MapeoDestinoExterno.Split(',');
                    foreach (string destinoMapeo in destinoMapeoSplit)
                    {
                        if (destinoMapeo == registroDeDesvios.Destino)
                        {
                            if (existeDestinoUnico)
                            {
                                destinoDuplicado = true;
                                dbDestinoList2.Add(dbDm);
                            }

                            if (!existeDestinoUnico)
                            {
                                existeDestinoUnico = true;
                                dbDestinoList2.Add(dbDm);
                            }
                        }
                    }
                }

                if (existeDestinoUnico && !destinoDuplicado)
                {
                    dbDestinoList = dbDestinoList2;
                }
            }

            if (dbDestinoList.Count > 1)
            {
                StringBuilder b = new StringBuilder();
                foreach (var dbDm in dbDestinoList)
                {
                    b.Append(dbDm.Nombre);
                    b.Append(" ");
                }

                MensajeDeNotificacion(string.Format("Hay destinos multiples para el destino SAP {0} ({1})", registroDeDesvios.Destino, b.ToString()), TipoMensajeNotificacion.Error);
            }
            else
            {
                DbDestino dbDestino = dbDestinoList.SingleOrDefault();
                if (dbDestino == null)
                {
                    MensajeDeNotificacion(string.Format("No se encontró un destino relacionado para {0}", registroDeDesvios.Destino), TipoMensajeNotificacion.Error);
                }
                else
                {
                    dbPlanDeProduccion = ctx.DbPlanProduccions.FilterLogicalRemoved().Where(p => p.SincronizaSJ && p.TemporadaId == dbTemporada.Id && p.DestinoId == dbDestino.Id).SingleOrDefault();

                    if (dbPlanDeProduccion == null)
                    {
                        MensajeDeNotificacion(string.Format("No se encontró un plan de producción para Nombre simil: {0}, Destino: {1}", NombrePlan, dbDestino.Nombre), TipoMensajeNotificacion.Error);
                    }
                }

                // Con el plan, genero el desvio
                if (dbPlanDeProduccion != null)
                {
                    // Tengo el producto, => genero el desvío (ver como se generan los desvios masivos), no, genero el desvio acá

                    // El detalle es para un producto solamente, salvo en el caso de anulacion de primera a segunda
                    List<DesvioUpdate> updateDesvioList = new List<DesvioUpdate>();

                    // Tengo que hacer un análisis en función del tipo de pasaje mas profundo, para asignar los valores de segunda y los movimientos
                    CreateDetallesDelDesvio(updateDesvioList, dbPlanDeProduccion, dbTemporada, temporadaSemanaMesList, registroDeDesvios);

                    int tipoDesvioId = ObtenerTipoDesvio(registroDeDesvios); // TODO: completar mediante los codigos C+, DS, etc.
                    int motivoDesvioId = ObtenerMotivoDesvio(ctx, serviceOptions, registroDeDesvios); // TODO: completar mediante el campo motivo de desvio (solo figura F)

                    PlanProdAdminService planProdAdminService = new PlanProdAdminService();
                    IncorporarDesvioResult resultadoIncorporacion = planProdAdminService.IncorporarDesviosInternal(ctx, serviceOptions, dbPlanDeProduccion.Id, tipoDesvioId, motivoDesvioId, updateDesvioList, registroDeDesvios);

                    string mensajeNotificacionProceso = string.Format("El desvio para {0} {2} fue incorporado {1}. {3}", registroDeDesvios.ProductoCodigo, resultadoIncorporacion.IncorporadoOK ? "OK" : "NO OK", dbDestino.Nombre, resultadoIncorporacion.Mensaje);                    

                    MensajeDeNotificacion(mensajeNotificacionProceso, TipoMensajeNotificacion.Informacion);
                }
            }
        }

        private static Dictionary<string, string> tiposDict = new Dictionary<string, string>()
        {
            {"C-", "Disminución o caída de Prendas"},
            {"C+", "Agregado de Prendas"},
            {"R+", "Recupero de Prendas"},
            {"AS", "Anulación de Desdoble de Primera a Segunda"},
            {"DD", "Desdoble de Primera a Descarte"},
            {"DA", "Anulación de Desdoble Primera a Descarte"},
            {"DB", "Desdoble de Segunda a Descarte"},
            {"DC", "Anulación de Desdoble de Segunda a Descarte"},            
            {"F", "Movimiento de Fechas"},
            {"DS", "Desdoble de Primera a Segunda"},
        };

        private void CreateDetallesDelDesvio(List<DesvioUpdate> updateDesvioList, DbPlanProduccion dbPlanDeProduccion, DbTemporada dbTemporada, List<DbTemporadaSemanaMes> temporadaSemanaMesList, SanJuanRegistroDeDesvios registroDeDesvios)
        {
            // Obtengo el producto del desvio ya que si o si el desvio aplica al menos a un producto (quizas pueden ser dos)
            DbPlanProduccionDetalle dbPPDetalleProducto = dbPlanDeProduccion.PlanProduccionDetalles.Where(pd => pd.Producto.ProductoIdExterno == registroDeDesvios.ProductoCodigo8 && pd.Producto.ColorIdExterno == registroDeDesvios.ProductoColor3).SingleOrDefault();
            if (dbPPDetalleProducto == null)
            {
                MensajeDeNotificacion(string.Format("No se encontró el producto {0}, en el plan {1}", registroDeDesvios.ProductoCodigo, dbPlanDeProduccion.Nombre), TipoMensajeNotificacion.Informacion);
            }
            else
            {
                // Tengo que generar el desvio  (para la cantidad y producto) según el tipo de desvio ej: pasaje a segunda, o algún movimiento               
                registroDeDesvios.NumeroSemana = GetNumeroSemana(registroDeDesvios.Fecha, temporadaSemanaMesList);
                if (tiposDict.ContainsKey(registroDeDesvios.Tipo))
                {
                    registroDeDesvios.TipoDescripcion = tiposDict[registroDeDesvios.Tipo];
                }               

                DesvioUpdate desvioUpdate = new DesvioUpdate();
                desvioUpdate.ProductoId = dbPPDetalleProducto.ProductoId;
                updateDesvioList.Add(desvioUpdate);

                List<DesvioUpdateDetalle> desvioUpdateDetalleList = new List<DesvioUpdateDetalle>();
                desvioUpdate.Detalles = desvioUpdateDetalleList;
                // CAMBIOS
                //C-	Disminución o caída de Prendas.
                //C+	Agregado de Prendas.
                //R+	Recupero de Prendas.
                //AS	Anulación de Desdoble de Primera a Segunda.
                //DD	Desdoble de Primera a Descarte.
                //DA	Anulación de Desdoble Primera a Descarte.
                //DB	Desdoble de Segunda a Descarte.
                //DC	Anulación de Desdoble de Segunda a Descarte.
                if (registroDeDesvios.Tipo == "C-" ||  //C-	Disminución o caída de Prendas.
                    registroDeDesvios.Tipo == "DD" ||  //DD	Desdoble de Primera a Descarte.
                    registroDeDesvios.Tipo == "DB")    //DB	Desdoble de Segunda a Descarte.
                {
                    // Los tipos de desvíos que restan en la cantidad inicial
                    int numeroSemanaOrigen = GetNumeroSemana(registroDeDesvios.Fecha, temporadaSemanaMesList);
                    var dbDetalleOrigen = dbPPDetalleProducto.PlanProduccionDetalleCantidades.Where(c => c.NumeroSemana == numeroSemanaOrigen).Single();

                    // Son dos detalles de cambio, uno para cada semana
                    DesvioUpdateDetalle detalleOrigen = new DesvioUpdateDetalle();
                    detalleOrigen.Cantidad = dbDetalleOrigen.Cantidad - registroDeDesvios.Cantidad;
                    detalleOrigen.NumeroSemana = numeroSemanaOrigen;
                    desvioUpdateDetalleList.Add(detalleOrigen);
                }

                else if (registroDeDesvios.Tipo == "C+" ||  //C+	Agregado de Prendas.
                   registroDeDesvios.Tipo == "R+" ||        //R+	Recupero de Prendas.
                   registroDeDesvios.Tipo == "DA" ||        //DA	Anulación de Desdoble Primera a Descarte.
                    registroDeDesvios.Tipo == "DC")         //DC	Anulación de Desdoble de Segunda a Descarte.
                {
                    // Los tipos de desvíos que suman en la cantidad inicial
                    int numeroSemanaOrigen = GetNumeroSemana(registroDeDesvios.Fecha, temporadaSemanaMesList);
                    var dbDetalleOrigen = dbPPDetalleProducto.PlanProduccionDetalleCantidades.Where(c => c.NumeroSemana == numeroSemanaOrigen).Single();

                    // Son dos detalles de cambio, uno para cada semana
                    DesvioUpdateDetalle detalleOrigen = new DesvioUpdateDetalle();
                    detalleOrigen.Cantidad = dbDetalleOrigen.Cantidad + registroDeDesvios.Cantidad;
                    detalleOrigen.NumeroSemana = numeroSemanaOrigen;
                    desvioUpdateDetalleList.Add(detalleOrigen);
                }

                else if (registroDeDesvios.Tipo == "AS") //AS	Anulación de Desdoble de Primera a Segunda. (este caso no lo contempla el update, hago dos cambios, uno en primera y otro en segunda)
                {
                    // tengo que armar un desvio de aumento en primera y una caida en segunda
                    // el desvio de primera ya lo tengo creado, tengo que crear el de segunda
                    int numeroSemanaOrigen = GetNumeroSemana(registroDeDesvios.Fecha, temporadaSemanaMesList);

                    var dbDetalleOrigen = dbPPDetalleProducto.PlanProduccionDetalleCantidades.Where(c => c.NumeroSemana == numeroSemanaOrigen).Single();

                    DesvioUpdateDetalle detalleOrigen = new DesvioUpdateDetalle();
                    detalleOrigen.Cantidad = dbDetalleOrigen.Cantidad + registroDeDesvios.Cantidad;
                    detalleOrigen.NumeroSemana = numeroSemanaOrigen;
                    desvioUpdateDetalleList.Add(detalleOrigen);

                    // Creo el de segunda
                    DbPlanProduccionDetalle dbPPDetalleProductoSegunda = dbPlanDeProduccion.PlanProduccionDetalles.Where(pd => pd.ProductoId == dbPPDetalleProducto.Producto.ProductoSegundaId.Value).SingleOrDefault();
                    int cantidadPrexistente = 0;
                    if (dbPPDetalleProductoSegunda != null)
                    {
                        var dbDetalleSegunda = dbPPDetalleProductoSegunda.PlanProduccionDetalleCantidades.Where(c => c.NumeroSemana == numeroSemanaOrigen).Single();
                        if (dbDetalleSegunda != null)
                        {
                            cantidadPrexistente = dbDetalleSegunda.Cantidad;
                        }
                    }

                    DesvioUpdate desvioUpdateSegunda = new DesvioUpdate();
                    desvioUpdateSegunda.ProductoId = dbPPDetalleProducto.Producto.ProductoSegundaId.Value;
                    updateDesvioList.Add(desvioUpdateSegunda);
                    DesvioUpdateDetalle detalleOrigenSegunda = new DesvioUpdateDetalle();
                    detalleOrigenSegunda.Cantidad = cantidadPrexistente - registroDeDesvios.Cantidad;
                    detalleOrigenSegunda.NumeroSemana = numeroSemanaOrigen;

                    List<DesvioUpdateDetalle> desvioUpdateDetalleSegundaList = new List<DesvioUpdateDetalle>();
                    desvioUpdateDetalleSegundaList.Add(detalleOrigenSegunda);
                    desvioUpdateSegunda.Detalles = desvioUpdateDetalleSegundaList;
                }

                // MOVIMIENTOS
                //F	    Movimiento de Fechas.
                else if (registroDeDesvios.Tipo == "F")
                {
                    // Muevo según las fechas una determinada cantidad
                    int numeroSemanaOrigen = GetNumeroSemana(registroDeDesvios.Fecha, temporadaSemanaMesList);
                    int numeroSemanaDestino = GetNumeroSemana(registroDeDesvios.FechaNueva, temporadaSemanaMesList);

                    if (numeroSemanaDestino == numeroSemanaOrigen)
                    {
                        // En realidad no hay movimiento de semanas
                        desvioUpdateDetalleList.Clear();
                    }
                    else
                    {
                        var dbDetalleOrigen = dbPPDetalleProducto.PlanProduccionDetalleCantidades.Where(c => c.NumeroSemana == numeroSemanaOrigen).Single();
                        var dbDetalleDestino = dbPPDetalleProducto.PlanProduccionDetalleCantidades.Where(c => c.NumeroSemana == numeroSemanaDestino).Single();

                        // Son dos detalles de cambio, uno para cada semana
                        DesvioUpdateDetalle detalleOrigen = new DesvioUpdateDetalle();
                        detalleOrigen.Cantidad = dbDetalleOrigen.Cantidad - registroDeDesvios.Cantidad;
                        detalleOrigen.NumeroSemana = numeroSemanaOrigen;
                        desvioUpdateDetalleList.Add(detalleOrigen);

                        DesvioUpdateDetalle detalleDestino = new DesvioUpdateDetalle();
                        detalleDestino.Cantidad = registroDeDesvios.Cantidad;
                        detalleDestino.NumeroSemana = numeroSemanaDestino;
                        desvioUpdateDetalleList.Add(detalleDestino);
                    }
                }

                // PASAJE DE 1 a 2
                //DS	Desdoble de Primera a Segunda.
                else if (registroDeDesvios.Tipo == "DS")
                {
                    // Guardo el delta que tengo que pasar a segunda que según p torello es lo que me envía
                    int numeroSemanaOrigen = GetNumeroSemana(registroDeDesvios.Fecha, temporadaSemanaMesList);
                    DesvioUpdateDetalle detalleOrigen = new DesvioUpdateDetalle();
                    detalleOrigen.Cantidad = registroDeDesvios.Cantidad;
                    detalleOrigen.NumeroSemana = numeroSemanaOrigen;
                    desvioUpdateDetalleList.Add(detalleOrigen);
                }
            }
        }

        private int GetNumeroSemana(string fechaSAP, List<DbTemporadaSemanaMes> temporadaSemanaMesList)
        {
            DateTime fechaRegistroDesvio = DateTime.ParseExact(fechaSAP, "yyyy-MM-dd", null);
            var dbTemporadaSemana = temporadaSemanaMesList.Where(t => t.Desde <= fechaRegistroDesvio && t.Hasta > fechaRegistroDesvio).Single();
            return dbTemporadaSemana.NumeroSemana;
        }

        private int ObtenerMotivoDesvio(PlanProdEntities ctx, ServiceOptions serviceOptions, SanJuanRegistroDeDesvios registroDeDesvios)
        {
            string sapMotivoDesvio = registroDeDesvios.MotivoDesvio.ToString();
            //if (String.IsNullOrEmpty(sapMotivoDesvio))
            //{
            //    registroDeDesvios.MotivoDesvio = "Sin especificar";
            //}

            DbDesvioCausa dbDesvioCausa = ctx.DbDesvioCausas.Where(d => d.MapeoExterno == sapMotivoDesvio).SingleOrDefault();
            // Si no existe el motivo de desvio desde SAP lo agrego (según lo que envía SAP o agrego el motivo 'Sin especificar')
            if (dbDesvioCausa == null)
            {
                dbDesvioCausa = new DbDesvioCausa();
                ctx.DbDesvioCausas.AddObject(dbDesvioCausa);
                dbDesvioCausa.AuditFechaCreacion = DateTime.Now;
                dbDesvioCausa.AuditUserNameCreacion = serviceOptions.UserName;
                dbDesvioCausa.EmpresaId = serviceOptions.CompanyId;
                dbDesvioCausa.Nombre = sapMotivoDesvio;
                dbDesvioCausa.MapeoExterno = sapMotivoDesvio;
                ctx.SaveChanges();
            }

            return dbDesvioCausa.Id;
        }

        private int ObtenerTipoDesvio(SanJuanRegistroDeDesvios registroDeDesvios)
        {
            //C-	Disminución o caída de Prendas.
            //C+	Agregado de Prendas.
            //R+	Recupero de Prendas.
            //F	    Movimiento de Fechas.
            //DS	Desdoble de Primera a Segunda.
            //AS	Anulación de Desdoble de Primera a Segunda.
            //DD	Desdoble de Primera a Descarte.
            //DA	Anulación de Desdoble Primera a Descarte.
            //DB	Desdoble de Segunda a Descarte.
            //DC	Anulación de Desdoble de Segunda a Descarte.

            int tipoDesvio = 0;
            if (registroDeDesvios.Tipo == "C-")
            {
                tipoDesvio = (int)TipoDesvio.Cambio;
            }
            else if (registroDeDesvios.Tipo == "C+")
            {
                tipoDesvio = (int)TipoDesvio.Cambio;
            }
            else if (registroDeDesvios.Tipo == "R+")
            {
                tipoDesvio = (int)TipoDesvio.Cambio;
            }
            else if (registroDeDesvios.Tipo == "F")
            {
                tipoDesvio = (int)TipoDesvio.Movimiento;
            }
            else if (registroDeDesvios.Tipo == "DS")
            {
                tipoDesvio = (int)TipoDesvio.PasajeASegunda;
            }
            else if (registroDeDesvios.Tipo == "AS")
            {
                tipoDesvio = (int)TipoDesvio.Cambio;
            }
            else if (registroDeDesvios.Tipo == "DD")
            {
                tipoDesvio = (int)TipoDesvio.Cambio;
            }
            else if (registroDeDesvios.Tipo == "DA")
            {
                tipoDesvio = (int)TipoDesvio.Cambio;
            }
            else if (registroDeDesvios.Tipo == "DB")
            {
                tipoDesvio = (int)TipoDesvio.Cambio;
            }
            else if (registroDeDesvios.Tipo == "DC")
            {
                tipoDesvio = (int)TipoDesvio.Cambio;
            }

            return tipoDesvio;
        }

        /// <summary>
        /// Obtiene los desvios de SAP para una fecha agrupados x 
        /// novedad.FECHA + novedad.DESTINO + novedad.PRODUCTO + novedad.PRODUCTOSEGUNDA + novedad.TIPO + novedad.MOTIVODESVIO + novedad.FECHANUEVA;
        /// </summary>
        /// <param name="fecha"></param>
        /// <returns></returns>
        public virtual List<SanJuanRegistroDeDesvios> ObtenerDesviosDesdeSapAgrupadoPorFechaSumaCantidad(DateTime fecha)
        {
            #region Ejemplo de la respuesta del web service
            // Ejemplo de la respuesta del web service
            //TIPO: C+
            //CANTIDAD: 15
            //MOTIVODESVIO: 0
            //FECHANUEVA: 0000-00-00
            //FECHA: 2011-12-14
            //HORA: 16:59:36
            //DESTINO: DIFUSION
            //PRODUCTO: APCH4353R0S
            //PRODUCTOSEGUNDA:
            //TIPO: C+
            //CANTIDAD: 16
            //MOTIVODESVIO: 0
            //FECHANUEVA: 0000-00-00
            //FECHA: 2011-12-14
            //HORA: 16:59:37
            //DESTINO: DIFUSION
            //PRODUCTO: APCH4353R0S
            //PRODUCTOSEGUNDA:
            //            OT: string
            //            PAQUETE: 094
            //            COD_OPE_SAP D1
            #endregion

            List<SanJuanRegistroDeDesvios> desviosAgrupados = new List<SanJuanRegistroDeDesvios>();
            ZMM_WS_NOVEDADES_PRODUCCION_SJClient wcfClient = new ZMM_WS_NOVEDADES_PRODUCCION_SJClient();

            wcfClient.ClientCredentials.UserName.UserName = "gaci";
            wcfClient.ClientCredentials.UserName.Password = "gacivesuvio";

            ZMM_RESPUESTA_NOVEDADES[] novedades = new ZMM_RESPUESTA_NOVEDADES[1500];

            string fechaDesde = fecha.ToString("yyyyMMdd");

            wcfClient.ZMM_WS_NOVEDADES_PRODUCCION_SJ(ref novedades, fechaDesde, fechaDesde);

            Dictionary<string, List<ZMM_RESPUESTA_NOVEDADES>> hashNovedades = new Dictionary<string, List<ZMM_RESPUESTA_NOVEDADES>>();

            // Cargo las novedades agrupadas en un solo registro, agrupando

            // Primero agrupo las novedades en un hash table
            foreach (ZMM_RESPUESTA_NOVEDADES novedad in novedades)
            {
                if (novedad != null)
                {
                    string hashKey = novedad.FECHA + novedad.DESTINO + novedad.PRODUCTO + novedad.PRODUCTOSEGUNDA + novedad.TIPO + novedad.MOTIVODESVIO + novedad.FECHANUEVA;

                    List<ZMM_RESPUESTA_NOVEDADES> listaDeNovedadesParaUnKey;
                    if (hashNovedades.ContainsKey(hashKey))
                    {
                        listaDeNovedadesParaUnKey = hashNovedades[hashKey];
                    }
                    else
                    {
                        listaDeNovedadesParaUnKey = new List<ZMM_RESPUESTA_NOVEDADES>();
                        hashNovedades.Add(hashKey, listaDeNovedadesParaUnKey);
                    }

                    listaDeNovedadesParaUnKey.Add(novedad);
                }
            }

            // Ahora agrupo sumando las cantidades
            foreach (var key in hashNovedades.Keys)
            {
                List<ZMM_RESPUESTA_NOVEDADES> novedadesAgrupadas = (List<ZMM_RESPUESTA_NOVEDADES>)hashNovedades[key];

                SanJuanRegistroDeDesvios sanJuanRegistroDesvio = new SanJuanRegistroDeDesvios();
                ZMM_RESPUESTA_NOVEDADES novedadAgrupadaFirst = novedadesAgrupadas.First();

                sanJuanRegistroDesvio.ClaveNatural = key; // Esto es para que no se repita y se vuelva a procesar este registro.
                sanJuanRegistroDesvio.Fecha = novedadAgrupadaFirst.FECHA;
                sanJuanRegistroDesvio.Destino = novedadAgrupadaFirst.DESTINO;
                sanJuanRegistroDesvio.ProductoCodigo = novedadAgrupadaFirst.PRODUCTO;
                sanJuanRegistroDesvio.ProductoCodigoSegunda = novedadAgrupadaFirst.PRODUCTOSEGUNDA;
                sanJuanRegistroDesvio.Tipo = novedadAgrupadaFirst.TIPO;
                sanJuanRegistroDesvio.MotivoDesvio = novedadAgrupadaFirst.MOTIVODESVIO;
                sanJuanRegistroDesvio.FechaNueva = novedadAgrupadaFirst.FECHANUEVA;
                sanJuanRegistroDesvio.TemporadaMapeoExterno = novedadAgrupadaFirst.TEMPORADA;

                foreach (ZMM_RESPUESTA_NOVEDADES novedadAgrupada in novedadesAgrupadas)
                {
                    sanJuanRegistroDesvio.Cantidad += novedadAgrupada.CANTIDAD;
                    sanJuanRegistroDesvio.DetalleDeSap.Add(novedadAgrupada);
                }

                desviosAgrupados.Add(sanJuanRegistroDesvio);
            }

            return desviosAgrupados;
        }
    }
}
